package com.irdstudio.efp.esb.service.mock.zx;

import static com.irdstudio.basic.sequence.service.DefaultPatternDescriptor.DAY;
import static com.irdstudio.basic.sequence.service.DefaultPatternDescriptor.MIN;
import static com.irdstudio.basic.sequence.service.DefaultPatternDescriptor.MONTH;
import static com.irdstudio.basic.sequence.service.DefaultPatternDescriptor.SECOND;
import static com.irdstudio.basic.sequence.service.DefaultPatternDescriptor.SEQ;
import static com.irdstudio.basic.sequence.service.DefaultPatternDescriptor.YEAR_4;
import static java.util.Collections.singletonList;
import static java.util.Objects.requireNonNull;

import java.util.Base64;
import java.util.function.Function;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;

import com.irdstudio.basic.sequence.service.DefaultPatternDescriptor;
import com.irdstudio.basic.sequence.service.PatternDescriptor;
import com.irdstudio.basic.sequence.service.facade.PatternedLimitableSeqService;
import com.irdstudio.efp.esb.service.bo.req.BaseZXReqBean;
import com.irdstudio.efp.esb.service.bo.req.ZXQueryReports;
import com.irdstudio.efp.esb.service.bo.resp.zx.BaseZXResBean;
import com.irdstudio.efp.esb.service.bo.resp.zx.ZXResponseReport;
import com.irdstudio.efp.esb.service.facade.zx.ZXService;
import com.irdstudio.efp.esb.service.vo.zx.ZXVO;
import com.irdstudio.basic.framework.core.util.SpringContextUtils;

/**
 * @description:征信黑名单接口基类
 * @param <Q> 请求查询的报文类型
 * @param <P> 接口返回的结果类型
 * @date:2018年12月15日 上午10:29:31
 * @author:hengyh
 */
public abstract class BaseZXService<Q extends ZXQueryReports, P extends ZXResponseReport> implements ZXService<Q> {
	
	private static Logger log = LoggerFactory.getLogger(BaseZXService.class);
	
	public static final String ZX_SUCCESS_STATUS = "1";
	private static final PatternDescriptor pattern = 
			DefaultPatternDescriptor.of("ZX" + YEAR_4 + MONTH + DAY + MIN + SECOND + SEQ, 10);
	
	public ZXVO service(Q queryReports) throws Exception {
		log.info("处理卡中心接口开始， 请求参数：" + queryReports);
		ZXConfig config = ZXConfig.getInstance(); // assert config != null
		BaseZXReqBean<Q> reqBean = new BaseZXReqBean.Builder<Q>()
									.withSysId(config.getSystemId())
									.withUsrID(config.getUserId())
									.withPKey(config.getpKey())		
									.withRqsID(queryIdGenerate()) /* 生成唯一的queryId */
									.withQryRptsInfArry(singletonList(queryReports))
									.build();
		preProcess(reqBean);
		
//		EsbRespServiceBean esbRespServiceBean = ESBClientFactory.buildClient()
//												.withBody(reqBean)
//												.withTradeNo(tradeNo())
//												.withScene(scene())
//												.create()
//												.sendAndReceive();
//		EsbRespSysHeadBean esbRespSysHeadBean = esbRespServiceBean.getSysHead();
//		BaseZXResBean<P> resBean = esbRespServiceBean.getBody(converter());
//		if (Objects.equals(esbRespSysHeadBean.getRetSt(), "0")) {
//			StringBuilder errMsg = new StringBuilder("调用卡中心接口异常");
//			Optional.ofNullable(resBean).map(BaseZXResBean::getWrongInf)
//			.ifPresent(s -> errMsg.append(",错误信息: ").append(s));
//			throw new ESBException(errMsg.toString());
//		}
		BaseZXResBean<P> resBean = null;
		return postProcess(reqBean, resBean);
	}
	
	/* 对queryReports进行预处理（可选),由子类实现  */
	protected void preProcess(BaseZXReqBean<Q> reqBean) { };
	/* 对接口返回结果进行处理，并返回包装后的结果 */
	protected abstract ZXVO postProcess(BaseZXReqBean<Q> reqBean, BaseZXResBean<P> resBean) throws Exception;
	/* 各接口的交易码 */
	protected abstract String tradeNo();
	/* 各接口的服务场景 */
	protected abstract String scene();
	/* 各接口实现需提供将 返回JSON 转换为 Bean 的转换策略 */
	protected abstract Function<String , BaseZXResBean<P>> converter() ;
	
	private String queryIdGenerate() throws Exception {
		PatternedLimitableSeqService sequenceService = (PatternedLimitableSeqService) SpringContextUtils.getBean("defaultSeqService");
		return sequenceService.getPatternedSequence("ZX", pattern);
	}
	
	/**
	 * @description:征信接口的相关配置类
	 * 注意：此类仅作为本模块下的组件，不对外部模块暴露
	 * 注意：确保BaseZXService的子类在ZXConfig的bean被创建
	 * 之后创建（在子类上使用@DependsOn注解显式声明）
	 * 	
	 * @date:2018年12月15日 上午10:29:52
	 * @author:hengyh
	 */
	@Component("ZXConfig")
	@SuppressWarnings("unused")
	private static class ZXConfig implements InitializingBean {
		private static ZXConfig INSTANCE;
		
		@Value("${zx.systemId}")
		private String systemId;
		@Value("${zx.userId}")
		private String userId; 
		@Value("${zx.key}")
		private String key; 
		
		private String pKey;
		private final Base64.Encoder encoder = Base64.getEncoder();
		
		/** 在属性值初始化完成之后执行该方法 **/
		@Override
		public void afterPropertiesSet() throws Exception {
			/* pKey
			      通过组合key+,+systemId+,+userId得到字符串
			      通过字符串md5加密生成byte数组
			      对这个数组进行base64加密得到pKey。
			 */
			String temp = key + "," + systemId + "," + userId;
			pKey = new String(encoder.encode(DigestUtils.md5Digest(temp.getBytes("UTF-8"))));
			INSTANCE = this;
		}
		public static ZXConfig getInstance() { return requireNonNull(INSTANCE); }
		
		public String getSystemId() { return requireNonNull(systemId); }
		public String getUserId() { return requireNonNull(userId); }
		public String getKey() { return requireNonNull(key); }
		public String getpKey() { return requireNonNull(pKey); }
	}
}
